package org.example.his.common.auth;

import io.jsonwebtoken.*;

import java.util.Date;
import java.util.UUID;

public class JwtAuth {

    //有效时间,固定的，这里设置的是一天，如果要测试的话可以设置为5s。
    private static long ExpirationTime = 1000*60*60*24*365;
    //这个是密钥值，固定的，只存在服务器。
    private static String signature = "!Q@W#E$R^Y&U";

    /**
     * 这是JWT的测试加密算法，算法是HS256，返回一个拼接好的JWT字符串。
     * @param username
     * @param UserID
     * @return String jwtToken
     */
    public static String jwtEncipher(String username,String UserID){
        JwtBuilder jwtBuilder = Jwts.builder();
        String jwtToken = jwtBuilder
                //header
                .setHeaderParam("typ","JWT")
                .setHeaderParam("alg","HS256")
                //payload
                //这两个属性要来自数据库，登录的时候传进来
                .claim("username",username)
                .claim("UserID",UserID)
                //设置主题
                .setSubject("loginToken")
                //设置有效时间
                .setExpiration(new Date(System.currentTimeMillis()+ExpirationTime))
                //设置Id
                .setId(UUID.randomUUID().toString())
                //Signature
                .signWith(SignatureAlgorithm.HS256,signature)
                .compact();
        System.out.println(jwtToken);
        return jwtToken;
    }
    /**
     * 这是JWT的测试解密算法，根据JWT字符串获取其各个属性值。
     * 参数是一个token,返回一个String类型。
     */
    public static String jwtDecrypt(String token){
        //这里应该给一个token，我省略了，只展示算法格式。
        JwtParser jwtParser = Jwts.parser();
        //通过签名来解析token中的数据，返回一个Claims集合存储解析后的数据
        Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        System.out.println(claims.get("username"));
        System.out.println(claims.get("role"));
        System.out.println(claims.getId());
        System.out.println(claims.getSubject());
        System.out.println(claims.getExpiration());
        return (String) claims.get("username");
    }

    /**
     * 检验前端传入的token是否有效，主要还是检查时间上是否过期！
     * @param token
     * @return true or false
     */
    public static boolean checkToken(String token){
        if (token == null){
            return false;
        }
        JwtParser jwtParser = Jwts.parser();
        try {
            Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
        } catch (Exception e){
            return false;
        }
        return true;
    }

}
/*
//JWT有三部分，Header，payload,Signature。
{
"alg": "HS256",
"typ": "JWT"
}

iss (issuer)：签发人
exp (expiration time)：过期时间
sub (subject)：主题
aud (audience)：受众
nbf (Not Before)：生效时间
iat (Issued At)：签发时间
jti (JWT ID)：编号

{
"sub": "1234567890",
"name": "John Doe",
"age": "19"
}

密钥：
首先，需要指定一个密钥（secret）。
这个密钥只有服务器才知道，不能泄露给用户。
然后，使用 Header 里面指定的签名算法（默认是 HMAC SHA256），按照下面的公式产生签名。
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

算出签名以后，把 Header、Payload、Signature 三个部分拼成一个字符串，每个部分之间用"点"（.）分隔，就可以返回给用户。


前端:
前端存token json转字符串:
    localStorage.setItem('access-admin',JSON.stringify(response.data))
前端取token 字符串转json:
    created(){
        this.admin = JSON.parse(window.localStorage.getItem('access-admin'))
    }
前端将token传入到后端，并检验token合法性，前端需要写:
    const router = new VueRouter({
        mode: 'history',
        base: process.env.BASE_URL,
        routes
    })

    //在路由之前需要做的操作相当于过滤器
    router.beforeEach(to,from,next) => {
        if (to.path.startsWith('/login')){
            window.localStorage.removeItem('access-admin')
            next()
        } else {
            //获取之前存的token
            let admin = JSON.parse(window.localStorage.getItem('access-admin'))
            //token失效那么直接去登录
            if (!admin) {
                next({path: '/login'})
            } else {
                //检验token合法性
                axios({
                    url:'http://localhost:8080/checkToken',
                    method:'get',
                    //头部带上token
                    headers:{
                        token:admin.token
                    }
                }).then((response) => {
                    if (response.data == "fail"){
                        console.log("校验失败")
                        next({path: '/error'})
                    }
                })
                next()
              }
            }
          })

    //后端获取前端的header写法:
    @GetMapping("/checkToken")
    public Boolean checkToken(HttpServletRequest request){
        String token = request.getHeader("token");
        return JwtAuth.checkToken(token);
    }
* */
